/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 * */

// AmzServer - Tototoy's server model.
// Author: tonyjobmails@gmail.com (tonyhack).
//
// Define class ByteBufferDynamic.
//
// This is a dynamic length buffer, using for socket to receive/send data.
// This buffer contains two pointers, you can use these pointers to read/write
// data from/to it. Before you write any data to buffer, you should check the
// buffer is enough using function - "PreWrite" (this function can reallocate
// the buffer when the buffer is not enough), After reading/writing, you should
// shift the buffer using the function - "ReadShift/WriteShift".
// This ByteBufferDynamic supports ordering read and random read, but only
// supports ordering write.
// If need, compile with "_BYTE_BUFFER_DYNAMIC_CHECK", this will check
// overflow.
//

#ifndef __BYTE__BUFFER__DYNAMIC__H
#define __BYTE__BUFFER__DYNAMIC__H

#include <vector>

#include "common.h"
#include "buffer_define.h"

namespace amz{

// A wrapper of vector<char>
class SimpleByteBufferDynamic {
  typedef std::vector<char> BufferVector;
 public:
  SimpleByteBufferDynamic() {}
  ~SimpleByteBufferDynamic() {}

  bool PreWrite(const uint32 size) {
    if(this->buffer_.size() < size)
      this->buffer_.resize(size);
    return true;
  }
  char *RandomPointer(uint32 position) {
    return &this->buffer_[position];
  }
  char *HeadPointer() {
    return &this->buffer_[0];
  }

 private:
  BufferVector buffer_;
};

class ByteBufferDynamic{
  // buffer typedefs.
  typedef std::vector<char> BufferVector;
  typedef BufferVector::iterator BufferVectorIterator;

 public:
  explicit ByteBufferDynamic(uint32 unit_buffer_size = kUnitBuffSize) : buffer_size_(0), read_index_(0), write_index_(0), unit_buffer_size_(unit_buffer_size)
#ifdef _BYTE_BUFFER_DYNAMIC_CHECK
  , allocate_count_(0)
#endif
  {}

  ~ByteBufferDynamic() {}

  // Write the data to the buffer.
  // bool Write(const uint8 *data, uint32 size);

  // Check the buffer is enough, or reallocate the buffer.
  bool PreWrite(const uint32 size);

  // Get position of read/write index.
  inline uint32 ReadIndex() const {
    return this->read_index_;
  }
  inline uint32 WriteIndex() const {
    return this->write_index_;
  }

  ////////////////////////////////////////////////////////////
  // This methods give an ordering read/write scheme.
  // Get the pointer of read/write position.
  const char *ReadPointer() const {
    return &this->buffer_[this->read_index_];
  }
  char *WritePointer() {
    return &this->buffer_[this->write_index_];
  }

  // Get size of read/write.
  inline uint32 ReadSize() const {
#ifdef _BYTE_BUFFER_DYNAMIC_CHECK
    if(this->allocate_count_ >= max_count_)
      return 0;
#endif
    return this->write_index_ - this->read_index_;
  }
  inline uint32 WriteSize() const {
#ifdef _BYTE_BUFFER_DYNAMIC_CHECK
    if(this->allocate_count_ >= max_count_)
      return 0;
#endif
    return this->buffer_size_ - this->write_index_;
  }

  // shift the buffer after reading/writing.
  void ReadShift(uint32 size);
  void WriteShift(uint32 size);
  ////////////////////////////////////////////////////////////


  ////////////////////////////////////////////////////////////
  // This methods give an random read scheme.
  // Get the cosnt pointer of given position.
  const char *RandomReadPointer(uint32 position) const {
    return &this->buffer_[position];
  }
  // Get the read size of given position.
  inline uint32 RandomReadSize(uint32 position) const {
#ifdef _BYTE_BUFFER_DYNAMIC_CHECK
    if(this->allocate_count_ >= max_count_)
      return 0;
#endif
    return this->write_index_ - position;
  }
  // Shift the buffer of given size.
  void RandomReadShift(uint32 position, uint32 size);
  ////////////////////////////////////////////////////////////


  inline uint32 GetUnitBufferSize() const { return this->unit_buffer_size_; }

 private:
  // the real shift.
  void Shift(uint32 read_size, uint32 write_size);

  BufferVector buffer_;
  uint32 buffer_size_;
  uint32 read_index_;
  uint32 write_index_;
  
  // EveryTime need to allocate the buffer, this value is the append length.
  uint32 unit_buffer_size_;

#ifdef _BYTE_BUFFER_DYNAMIC_CHECK
  uint32 allocate_count_;
  const uint32 max_count_ = kuint32max / this->unit_buffer_size_;
#endif
};

}  // namespace amz

#endif  // __BYTE__BUFFER__DYNAMIC__H

